﻿using AutoMapper;
using IOA.MES.Common;
using IOA.MES.DataAccess.Entity;
using IOA.MES.DataAccess.Enum;
using IOA.MES.DataAccess.VModel;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace IOA.MES.Business
{
    /// <summary>
    /// 发货管理（错误代码：127001）
    /// </summary>
    public class DeliveryMgr
    {
        private Logger logger = LogManager.GetCurrentClassLogger();
        private MESContext mesDb = new MESContext("MES");

        /// <summary>
        /// 查询发货单列表
        /// </summary>
        /// <param name="page">页面索引</param>
        /// <param name="limit">页面容量</param>
        /// <param name="total">全部数量</param>
        /// <param name="warehouseCode">仓库代码</param>
        /// <param name="deliveryOrderNo">发货单号</param>
        /// <param name="orderNo">合同编号</param>
        /// <param name="customer">客户信息</param>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">截止日期</param>
        /// <returns>发货单列表</returns>
        public List<VDeliveryOrder> QueryDeliveryOrders(int page, int limit, out int total, string warehouseCode, string deliveryOrderNo, string orderNo, string customer, DateTime startDate, DateTime endDate)
        {
            var query = from delivery in mesDb.DeliveryOrders.AsNoTracking().Where(_ => _.DeliveryDate >= startDate && _.DeliveryDate <= endDate && _.Valid)
                        select delivery;
            if (!string.IsNullOrWhiteSpace(warehouseCode))
            {
                query = query.Where(_ => _.WarehouseCode == warehouseCode);
            }
            if (!string.IsNullOrWhiteSpace(deliveryOrderNo))
            {
                query = query.Where(_ => _.DeliveryNo == deliveryOrderNo);
            }
            if (!string.IsNullOrWhiteSpace(orderNo))
            {
                query = query.Where(_ => _.OrderNo == orderNo);
            }
            if (!string.IsNullOrWhiteSpace(customer))
            {
                query = query.Where(_ => _.CustomerCode.Contains(customer) || _.CustomerName.Contains(customer));
            }

            total = query.Count();
            var entities = query.OrderByDescending(_ => _.DeliveryDate).Skip((page - 1) * limit).Take(limit).ToList();
            return Mapper.Map<List<VDeliveryOrder>>(entities);
        }

        /// <summary>
        /// 获取发货单对象
        /// </summary>
        /// <param name="deliveryNo">发货单号</param>
        /// <returns>发货单对象</returns>
        public VDeliveryOrder GetDelivery(string deliveryNo)
        {
            var entity = mesDb.DeliveryOrders.AsNoTracking().FirstOrDefault(_ => _.DeliveryNo == deliveryNo && _.Valid);
            var model = Mapper.Map<VDeliveryOrder>(entity);
            if (model != null)
            {
                model.Cabinets = Mapper.Map<List<VDeliveryCabinet>>(mesDb.DeliveryCabinets.AsNoTracking().Where(_ => _.DeliveryNo == deliveryNo && _.Valid).ToList());
            }
            return model;
        }

        /// <summary>
        /// 保存发货单柜号
        /// </summary>
        /// <param name="model">发货单对象</param>
        /// <param name="cabinetNos">柜号列表</param>
        public void SaveDeliveryCabinets(VDeliveryOrder model, List<string> cabinetNos)
        {
            var entity = mesDb.DeliveryOrders.AsNoTracking().FirstOrDefault(_ => _.DeliveryNo == model.DeliveryNo && _.Valid);
            if (entity == null)
            {
                throw new MultiLanBizException(127003);//当前发货单不存在
            }
            else if (entity.Status != DeliveryStatus.New)
            {
                throw new MultiLanBizException(127001);//当前状态无法保存柜号
            }
            cabinetNos = cabinetNos == null ? new List<string>() : cabinetNos.Where(_ => !string.IsNullOrWhiteSpace(_)).Select(_ => _.Trim().ToUpper()).Distinct().ToList();
            var cabinets = !cabinetNos.Any() ? new List<Cabinet>()
                : mesDb.Cabinets.AsNoTracking().
                Where(_ => cabinetNos.Contains(_.CabinetNo) && _.Valid && _.Status == CabinetStatus.Normal).ToList();
            var inValidCabinetNos = cabinetNos.Where(_ =>  !cabinets.Select(c => c.CabinetNo).Contains(_, StringComparer.CurrentCultureIgnoreCase)).ToList();
            if (inValidCabinetNos.Any())
            {
                throw new MultiLanBizException(127002, string.Join("、", inValidCabinetNos));//下列柜号不存在
            }

            var otherDeliveryCabinets = (from order in mesDb.DeliveryOrders.AsNoTracking()
                                         join cabinet in mesDb.DeliveryCabinets.AsNoTracking() on order.DeliveryNo equals cabinet.DeliveryNo
                                         where order.DeliveryNo != model.DeliveryNo && order.Valid && order.Status != DataAccess.Enum.DeliveryStatus.Canceled
                                         && cabinetNos.Contains(cabinet.CabinetNo) && cabinet.Valid
                                         select cabinet
                                       ).Distinct().ToList();
            if (otherDeliveryCabinets.Any())
            {
                throw new MultiLanBizException(127005, string.Join("、", otherDeliveryCabinets.Select(_ => $"{_.CabinetNo}：{_.DeliveryNo}").ToList()));//下列柜号已在其他发货单中：
            }

            var existCabinets = mesDb.DeliveryCabinets.AsNoTracking().Where(_ => _.DeliveryNo == model.DeliveryNo && _.Valid).ToList();
            var newCabinets = cabinets.Where(c => !existCabinets.Select(_ => _.CabinetNo).Contains(c.CabinetNo)).Select(_ => new DeliveryCabinet
            {
                CabinetNo = _.CabinetNo,
                DeliveryNo = model.DeliveryNo,
                OrderNo = _.OrderNo,
                InnerOrderNo = _.InnerOrderNo,
                WorkOrderNo = _.WorkOrderNo,
                QLevel = _.QLevel,
                IVPowerLevel = _.IVPowerLevel,
                IVCurrentLevel = _.IVCurrentLevel,
                ProductCode = _.ProductCode,
                ProductName = _.ProductName,
                ProductSpecs = _.ProductSpecs,
                NameplateModel = _.NameplateModel,
                ComponentColor = _.ComponentColor,
                PackQuantity = _.PackQuantity,
                AluFrameFactory = _.AluFrameFactory,
                AluFrameSpecs = _.AluFrameSpecs,
                BackPlanFactory = _.BackPlanFactory,
                BackPlanSpecs = _.BackPlanSpecs,
                BatteryFactory = _.BatteryFactory,
                BatterySpecs = _.BatterySpecs,
                JunBoxFactory = _.JunBoxFactory,
                JunBoxSpecs = _.JunBoxSpecs,
                CreateBy = model.ModifyBy,
                CreateTime = DateTime.Now
            }).ToList();
            var removeCabinets = existCabinets.Where(_ => !cabinetNos.Contains(_.CabinetNo, StringComparer.CurrentCultureIgnoreCase) && _.Valid).ToList();
            removeCabinets.ForEach(_ =>
            {
                mesDb.DeliveryCabinets.Attach(_);
                _.ModifyBy = model.ModifyBy;
                _.ModifyTime = DateTime.Now;
                _.Valid = false;
            });
            mesDb.DeliveryCabinets.AddRange(newCabinets);

            mesDb.SaveChanges();
        }

        /// <summary>
        /// 确认发货
        /// </summary>
        /// <param name="model">发货对象</param>
        public void SubmitDelivery(VDeliveryOrder model)
        {
            var entity = mesDb.DeliveryOrders.AsNoTracking().FirstOrDefault(_ => _.DeliveryNo == model.DeliveryNo && _.Valid);
            if (entity == null)
            {
                throw new MultiLanBizException(127003);//当前发货单不存在
            }
            else if (entity.Status != DataAccess.Enum.DeliveryStatus.New)
            {
                throw new MultiLanBizException(127004);//发货单已提交，无法重复操作
            }

            mesDb.DeliveryOrders.Attach(entity);
            entity.Status = DataAccess.Enum.DeliveryStatus.WaitingForDelivery;
            entity.ModifyBy = model.ModifyBy;
            entity.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    var cabinetNos = mesDb.DeliveryCabinets.AsNoTracking().Where(_ => _.DeliveryNo == model.DeliveryNo && _.Valid).Select(_ => _.CabinetNo).ToList();
                    var cabinets = mesDb.Cabinets.AsNoTracking().Where(_ => cabinetNos.Contains(_.CabinetNo) && _.Valid).ToList();

                    var outbounds = cabinets.Select(_ => new Outbound
                    {
                        WarehouseCode = _.WarehouseCode,
                        WarehouseName = _.WarehouseName,
                        CabinetNo = _.CabinetNo,
                        OutboundType = DataAccess.Enum.OutboundType.DeliveryOutbound,
                        OutboundNo = "",
                        OutboundTypeId = entity.PkId,
                        OutboundTypeNo = entity.DeliveryNo,
                        Quantity = _.PackQuantity,
                        Status = DataAccess.Enum.OutboundStatus.UnFinished,
                        CreateBy = model.ModifyBy,
                        CreateTime = DateTime.Now
                    }).ToList();
                    mesDb.Outbounds.AddRange(outbounds);

                    var loadInspects = cabinets.Select(_ => new LoadInspect
                    {
                        LoadStatus = DataAccess.Enum.LoadStatus.Loading,
                        DeliveryNo = entity.DeliveryNo,
                        CabinetNo = _.CabinetNo,
                        Quantity = _.PackQuantity,
                        CreateBy = model.ModifyBy,
                        CreateTime = DateTime.Now
                    }).ToList();
                    mesDb.LoadInspects.AddRange(loadInspects);
                    mesDb.SaveChanges();

                    outbounds.ForEach(_ =>
                    {
                        _.OutboundNo = $"{DateTime.Today:yyMMdd}{(_.PkId % 100000).ToString("00000")}";
                    });
                    foreach (var outbound in outbounds)
                    {
                        var outboundPacks = mesDb.CabinetPacks.AsNoTracking().Where(_ => _.CabinetNo == outbound.CabinetNo && _.Valid).ToList().Select(_ => new OutboundPack
                        {
                            WarehouseCode = _.WarehouseCode,
                            WarehouseName = _.WarehouseName,
                            AreaCode = _.AreaCode,
                            AreaName = _.AreaName,
                            PackBatchNo = _.PackBatchNo,
                            PackNo = _.PackNo,
                            Location = _.Location,
                            CreateBy = model.ModifyBy,
                            CreateTime = DateTime.Now,
                            OutboundNo = outbound.OutboundNo,
                            Outbounded = false
                        }).ToList();
                        mesDb.OutboundPacks.AddRange(outboundPacks);
                    }
                    foreach (var load in loadInspects)
                    {
                        var loadPacks = mesDb.CabinetPacks.AsNoTracking().Where(_ => _.CabinetNo == load.CabinetNo && _.Valid).ToList().Select(_ => new LoadPack
                        {
                            LoadId = load.PkId,
                            PackBatchNo = _.PackBatchNo,
                            PackNo = _.PackNo,
                            Loaded = false,
                            CreateBy = model.ModifyBy,
                            CreateTime = DateTime.Now
                        }).ToList();
                        mesDb.LoadPacks.AddRange(loadPacks);
                    }
                    mesDb.SaveChanges();
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"提交发货单异常，发货单号：{model.DeliveryNo}，异常信息：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 查询发货清单
        /// </summary>
        /// <param name="deliveryNo">发货单号</param>
        /// <returns>柜号清单</returns>
        public List<VDeliveryCabinet> QueryDeliveryProducts(string deliveryNo)
        {
            var entities = mesDb.DeliveryCabinets.AsNoTracking().Where(_ => _.DeliveryNo == deliveryNo && _.Valid).OrderBy(_ => _.CabinetNo).ToList();
            var models = Mapper.Map<List<VDeliveryCabinet>>(entities);
            return models;
        }

        /// <summary>
        /// 保存发货单
        /// </summary>
        public void SaveDelivery(VDeliveryOrder model)
        {
            var warehouse = mesDb.Warehouses.AsNoTracking().FirstOrDefault(_ => _.Valid && _.WarehouseCode == model.WarehouseCode);
            model.WarehouseName = warehouse?.WarehouseName;

            var entity = mesDb.DeliveryOrders.AsNoTracking().FirstOrDefault(_ => _.Valid && _.DeliveryNo == model.DeliveryNo);
            if (entity == null)
            {
                entity = Mapper.Map<DeliveryOrder>(model);
                entity.CreateTime = DateTime.Now;
                mesDb.DeliveryOrders.Add(entity);
            }
            else
            {
                mesDb.DeliveryOrders.Attach(entity);
                entity.OrderNo = model.OrderNo;
                entity.ContractNo = model.ContractNo;
                entity.WarehouseCode = model.WarehouseCode;
                entity.WarehouseName = model.WarehouseName;
                entity.CustomerCode = model.CustomerCode;
                entity.CustomerName = model.CustomerName;
                entity.DeliveryDate = model.DeliveryDate;
                entity.Count = model.Count;
                entity.ModifyBy = model.ModifyBy;
                entity.ModifyTime = DateTime.Now;
            }
            mesDb.SaveChanges();
        }
    }
}
